/* 
 * File:   SDRS.cpp
 * Author: liuyi
 * 
 * Created on July 21, 2009, 10:58 AM
 */

#include "SDRS.h"
#include "Debug.h"
#include "Config.h"
#include "Detector.h"
#include "OCR.h"
#include "CharFeature.h"
#include "CharExtracter.h"

#include <cassert>

#include <string>

vector<vector<ushort> *> SDRS::m_keywordList;

int SDRS::detectKeyword(const uchar *greyData, int width, int height) {
    vector<ushort> result;
    retrieve(result, greyData, width, height);

    if(result.size() == 0) {
        return 0;
    }
    
    int size = m_keywordList.size();
    int index;
    for(int i = 0; i < size; i++) {
        index = findFirstIndex(result, *m_keywordList.at(i));
        
        if(index != -1) {
            return 2;
        }
    }

    return 1;
}

void SDRS::retrieve(vector<ushort> &result, const uchar *greyData, int width, int height) {
    result.clear();

    int regionUp = (int)(Config::getInstance().getRegionIgnoreUp() * height);
    int regionDown = (int)(Config::getInstance().getRegionIgnoreDown() * height);

    if (regionUp > 0) {
        retrieveInRegion(result, greyData, width, regionUp);
    }

    if (regionDown < height) {
        retrieveInRegion(result, greyData + width*regionDown*sizeof (uchar), width, height-regionDown);
    }

#ifdef SHOW_SUBTITLE
    int len = result.size();
    if(len == 0) {
        return;
    }
    
    cout << "recognized " << len << " characters：" << endl;

    for (int j = 0; j < len; j++) {
        printf("%C", result.at(j));
    }
#endif
}

void SDRS::retrieveInRegion(vector<ushort> &result, const uchar *greyData, int width, int height) {
    vector<Detector::ROI *> roiList;
    Detector::detect(roiList, greyData, width, height);

    uchar *buffer = NULL;
    Detector::ROI *roi = NULL;
    
    vector<uchar*> picList;
    vector<int> widthList, heightList;

    int size = roiList.size();
    for(int i = 0; i < size; i++) {
        roi = roiList.at(i);

        // TODO: may be optimized by using buffer
        buffer = new uchar[roi->width * roi->height];
        CharExtracter::binarize(buffer, roi->data, roi->width, roi->height);

        picList.clear();
        widthList.clear();
        heightList.clear();
        if (!CharExtracter::divideChar(buffer, roi->width, roi->height, picList, widthList, heightList)) {
            delete []buffer;
            buffer = NULL;
            
            continue;
        }

#ifdef SHOW_DIVIDED_CHAR_IN_TOTAL
        Debug::showImageData(buffer, roi->width, roi->height);
#endif

        int len = picList.size();
        if (len == 0) {
            delete []buffer;
            continue;
        }

        ushort res;
        for (int offset = 0; offset < len; offset++) {
            res = OCR::recognize(picList[offset], widthList[offset], heightList[offset]);
            result.push_back(res);
        }
        result.push_back((ushort)L'\n');

        for (int i = 0; i < len; i++) {
            delete[] picList.at(i);
        }

        delete []buffer;
    }

    for(int i = 0; i < size; i++) {
        roi = roiList.at(i);

        delete []roi->data;
        delete roi;
    }
}


int SDRS::findFirstIndex(const vector<ushort> &str, const vector<ushort> &sub) {
    int strSize = str.size();
    int subSize = sub.size();
    if (strSize < subSize) {
        return -1;
    }

    for (int i = 0; i < strSize - subSize + 1; i++) {
        if (str[i] == sub[0]) {
            int j;
            for (j = 0; j < subSize && str[i + j] == sub[j]; j++) {
            }

            if (j == subSize) {
                return i;
            }
        }
    }

    return -1;
}

void SDRS::init(const string &configFilePath) {    
    Config::init(configFilePath);

    locale::global(locale(Config::getInstance().getLocale()));
    
    // move lazy initializing here to avoid multithread problem
    CharFeature::getInstance();
    OCR::preRecognize();

    const char *keywordPath = Config::getInstance().getKeywordPath();
    wifstream wfin(keywordPath);
    wstring line;
    vector<ushort> *temp = NULL;
    int len;
    
    while (!wfin.eof()) {
        getline(wfin, line);
        if ((len = line.length()) > 0) {
            temp = new vector<ushort>;
            for(int i = 0; i < len; i++) {
                temp->push_back((ushort)line[i]);
            }

            m_keywordList.push_back(temp);
        }
    }
    wfin.close();
}

void SDRS::release() {
    int size = m_keywordList.size();
    for(int i = 0; i < size; i++) {
        delete m_keywordList.at(i);
    }

    OCR::release();
}
